package com.tevintao.marketingsystem.tool;

import android.view.View;

import com.tevintao.marketingsystem.log.LogManager;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by tevintao on 2016/4/13.
 */
public class ClassTool {

    public static List<Method> getAllMethod(Class cls, String methodName) {
        List<Method> listMember = new ArrayList<>();
        List<Class<?>[]> listParameters = new ArrayList<>();
        Class<?> clazz = cls;
        while (clazz != null) {
            try {
                for (Method method : clazz.getDeclaredMethods())
                    if (method.getName().equals(methodName) && !Modifier.isAbstract(method.getModifiers())) {

                        // Check for same function in sub class
                        boolean different = true;
                        for (Class<?>[] parameters : listParameters) {
                            boolean same = (parameters.length == method.getParameterTypes().length);
                            for (int p = 0; same && p < parameters.length; p++)
                                if (!parameters[p].equals(method.getParameterTypes()[p])) {
                                    same = false;
                                    break;
                                }
                            if (same) {
                                different = false;
                                break;
                            }
                        }

                        if (different) {
                            listMember.add(method);
                            listParameters.add(method.getParameterTypes());
                        }
                    }
                clazz = clazz.getSuperclass();
            } catch (Throwable ex) {
                if (ex.getClass().equals(ClassNotFoundException.class) || ex.getClass().equals(NoClassDefFoundError.class))
                    break;
                else
                    throw ex;
            }
        }
        return listMember;
    }


    public static View.OnClickListener getViewOnClickListener(View cv) {
//        LogManager.getInstance().logInfo(" mCheckBtn hasOnClickListeners = " + cv.hasOnClickListeners());
        Class cls = cv.getClass();
        List<Method> methods = ClassTool.getAllMethod(cls, "getListenerInfo");
        for (Method method : methods) {
            LogManager.getInstance().logError(method.toString());
        }
        if (methods.size() > 0) {
            Method method = methods.get(0);
            method.setAccessible(true);
            try {
                Object listenerObj = method.invoke(cv);
                LogManager.getInstance().logInfo("listenerObj = " + listenerObj);

                Class ListenerCls = listenerObj.getClass();
                Field onClickListener = ListenerCls.getDeclaredField("mOnClickListener");
                Object ClickListenerObject = onClickListener.get(listenerObj);
//                LogManager.getInstance().logInfo("clickObje = " + ClickListenerObject + "   ||  clickObje instanceof View.OnClickListener = " + (ClickListenerObject instanceof View.OnClickListener));
                if (ClickListenerObject instanceof View.OnClickListener) {
                    return (View.OnClickListener) ClickListenerObject;
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public static Object getViewOnTouchListener(View cv) {
//        LogManager.getInstance().logInfo(" mCheckBtn hasOnClickListeners = " + cv.hasOnClickListeners());
        Class cls = cv.getClass();
        List<Method> methods = ClassTool.getAllMethod(cls, "getListenerInfo");
        for (Method method : methods) {
            LogManager.getInstance().logError(method.toString());
        }
        if (methods.size() > 0) {
            Method method = methods.get(0);
            method.setAccessible(true);
            try {
                Object listenerObj = method.invoke(cv);
                return listenerObj;
//                LogManager.getInstance().logInfo("listenerObj = " + listenerObj);
//
//                Class ListenerCls = listenerObj.getClass();
//                Field onClickListener = ListenerCls.getDeclaredField("mOnTouchListener");
//                Object ClickListenerObject = onClickListener.get(listenerObj);
//                return onClickListener;
//                LogManager.getInstance().logInfo("clickObje = " + ClickListenerObject + "   ||  clickObje instanceof View.OnClickListener = " + (ClickListenerObject instanceof View.OnClickListener));
//                if (ClickListenerObject instanceof View.OnClickListener) {
//                    return (View.OnClickListener) ClickListenerObject;
//                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } /*catch (NoSuchFieldException e) {
                e.printStackTrace();
            }*/
        }
        return null;
    }

    public static void printAllField(Object object) {
        if (null == object) {
            return;
        }

        Class<?> clazz = object.getClass();
        while (clazz != null) {
            LogManager.getInstance().logInfo("clazz = " + clazz);
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                try {
                    Object fieldObj = field.get(object);
                    LogManager.getInstance().logInfo("fieldName = " + field.getName() + " fieldObj = " + fieldObj + " class = " + (null == fieldObj ? " null " : fieldObj.getClass()));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    LogManager.getInstance().logError("IllegalAccessException  fieldName = " + field.getName());
                }
            }
            LogManager.getInstance().logInfo("----------------------------");
            for (Method method : clazz.getDeclaredMethods()) {
                LogManager.getInstance().logInfo("method = " + method);
            }
            clazz = clazz.getSuperclass();
        }
    }

    public static void justPrintAllField(Object object) {
        if (null == object) {
            return;
        }

        Class<?> clazz = object.getClass();
        LogManager.getInstance().logInfo("clazz = " + clazz);
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            try {
                Object fieldObj = field.get(object);
                LogManager.getInstance().logInfo("fieldName = " + field.getName() + " fieldObj = " + fieldObj + " class = " + (null == fieldObj ? " null " : fieldObj.getClass()));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                LogManager.getInstance().logError("IllegalAccessException  fieldName = " + field.getName());
            }
        }
        clazz = clazz.getSuperclass();
        LogManager.getInstance().logInfo("clazz = " + clazz);
        if (null != clazz) {
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                try {
                    Object fieldObj = field.get(object);
                    LogManager.getInstance().logInfo("fieldName = " + field.getName() + " fieldObj = " + fieldObj + " class = " + (null == fieldObj ? " null " : fieldObj.getClass()));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    LogManager.getInstance().logError("IllegalAccessException  fieldName = " + field.getName());
                }
            }
        }
        clazz = clazz.getSuperclass();
        LogManager.getInstance().logInfo("clazz = " + clazz);
        if (null != clazz) {
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                try {
                    Object fieldObj = field.get(object);
                    LogManager.getInstance().logInfo("fieldName = " + field.getName() + " fieldObj = " + fieldObj + " class = " + (null == fieldObj ? " null " : fieldObj.getClass()));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    LogManager.getInstance().logError("IllegalAccessException  fieldName = " + field.getName());
                }
            }
        }
    }

    public static void PrintGiveFieldAllFiled(Object object, String filedName) {
        if (null == object) {
            LogManager.getInstance().logInfo("PrintGiveFieldAllFiled null == object");
            return;
        }

        Class<?> clazz = object.getClass();
        try {
            Field declaredField = clazz.getDeclaredField(filedName);
            declaredField.setAccessible(true);
            Object o = declaredField.get(object);
            justPrintAllField(o);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("PrintGiveFieldAllFiled NoSuchFieldException filedName = " + filedName);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("PrintGiveFieldAllFiled IllegalAccessException filedName = " + filedName);
        }

    }

    public static Object getFiled(Object object, String filedName) {
        if (null == object) {
            LogManager.getInstance().logInfo("PrintGiveFieldAllFiled null == object");
            return null;
        }

        Class<?> clazz = object.getClass();
        Field field = null;

        while (clazz != null) {
            try {
                field = clazz.getDeclaredField(filedName);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }

            if (null != field) {
                break;
            } else {
                clazz = clazz.getSuperclass();
            }
        }

        if (null != field)
        try {
            field.setAccessible(true);
            Object o = field.get(object);
            return o;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("PrintGiveFieldAllFiled IllegalAccessException filedName = " + filedName);
        }

        return null;
    }
}
